using System;
using System.Collections.Generic;
using System.Text;

namespace Woz
{
    /// <summary>
    /// the base action class that implements both idisposable and icloneable
    /// </summary>
    public abstract class Action
    {
        /// <summary>
        /// the action constructor
        /// </summary>
        public Action()
        {
            // by default the screen this action is performed on is the current screen
            this.mScreen = Woz.ScreenManager.Instance.SelectedScreen;
        }

        /// <summary>
        /// gets the screen the action was performed on
        /// </summary>
        public Woz.Screen Screen
        {
            get
            {
                return this.mScreen;
            }
        }

        /// <summary>
        /// the name of the tool this action was fired from
        /// </summary>
        public abstract string ToolName { get; }

        /// <summary>
        /// gets whether this action can be propagated or not
        /// </summary>
        public abstract bool Propagatable { get; }

        /// <summary>
        /// the actual execution code goes here
        /// </summary>
        /// <param name="pScreen">the screen to execute action on</param>
        protected abstract void OnExecute(Woz.Screen pScreen);

        /// <summary>
        /// the actual unexecution code goes here
        /// </summary>
        /// <param name="pScreen">the screen to unexecute action on</param>
        protected abstract void OnUnExecute(Woz.Screen pScreen);

        /// <summary>
        /// execute the action and fire the executed event
        /// </summary>
        public void Execute()
        {
            // first switch to the screen we were on originally
            Woz.ScreenManager.Instance.SelectedScreen = this.mScreen;

            // call our abstract method for this
            this.OnExecute(this.mScreen);

            // fire our event for this
            // mhn- should cause an exception if you didnt use the action manager
            //if (this.Executed != null)
            {
               this.Executed.Invoke(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// unexecute the action and fire the unexecute event
        /// </summary>
        public void UnExecute()
        {
            // first switch to the screen we were on originally
            Woz.ScreenManager.Instance.SelectedScreen = this.mScreen;

            // call our abstract method for this
            this.OnUnExecute(this.mScreen);

            // fire our event for this
            // mhn- should cause an exception if you didnt use the action manager
            //if (this.UnExecuted != null)
            {
                this.UnExecuted.Invoke(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// apply the action to the given screen
        /// </summary>
        /// <param name="pScreen"></param>
        public void ApplyTo(Woz.Screen pScreen)
        {
            // turn is propagating flag on
            this.mIsPropagating = true;

            // execute the action on the given screen
            this.OnExecute(pScreen);

            // turn is propagating flag off
            this.mIsPropagating = false;
        }

        /// <summary>
        /// un apply the action to the given screen
        /// </summary>
        /// <param name="pScreen">the screen to un apply the action to</param>
        public void UnApplyTo(Woz.Screen pScreen)
        {
            // turn is propagating flag on
            this.mIsPropagating = true;

            // unexecute the action on the given screen
            this.OnUnExecute(pScreen);

            // turn is propagating flag off
            this.mIsPropagating = false;
        }

        /// <summary>
        /// check to see if this action can be applied to the given screen
        /// </summary>
        /// <param name="pScreen">the screen to check against</param>
        /// <returns>true if the action can be applied to the given screen</returns>
        public virtual bool CanApplyTo(Woz.Screen pScreen)
        {
            return false;
        }

        /// <summary>
        /// converts the action into a useful string
        /// </summary>
        /// <returns>the string representation of the action</returns>
        public override string ToString()
        {
            return (this.mActionString == null) ? base.ToString() : this.mActionString;
        }

        /// <summary>
        /// fires when an action has been executed
        /// </summary>
        public event EventHandler Executed;
        
        /// <summary>
        /// fires when an action has been unexecuted
        /// </summary>
        public event EventHandler UnExecuted;

        /// <summary>
        /// the screen this action should be executed and unexecuted on
        /// by default this is the screen that was current when this action was instanciated
        /// </summary>
        protected Woz.Screen mScreen;

        /// <summary>
        /// the action string that is used in all of the actions
        /// </summary>
        protected string mActionString;

        /// <summary>
        /// the action is being propagated to a screen
        /// </summary>
        protected bool mIsPropagating;
    }
}
